package search.service.graph;

import com.thinkaurelius.titan.core.TitanGraph;
import common.model.graph.CommonSchema;
import common.model.graph.ConceptSchema;
import common.model.graph.InstanceSchema;
import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal;
import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
import org.apache.tinkerpop.gremlin.structure.Vertex;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import org.springframework.stereotype.Component;
import search.config.AnalyzerNames;
import common.dao.elastic.ElasticSearchDao;
import common.dao.gremlin.TitanGraphDao;
import search.service.analysis.AnalysisService;

import javax.inject.Inject;
import java.util.*;

/**
 * Created by Common on 8/31/16.
 */
@Component
public class EntityExpansionService {
    final Logger logger = LoggerFactory.getLogger(EntityExpansionService.class);

    private ElasticSearchDao esDao;
    //private TitanGraphDao titandb;
    //private TitanGraph graph;
    private GraphTraversalSource g;

    @Inject
    public EntityExpansionService(
            ElasticSearchDao esDao
            //,TitanGraphDao titandb
    ){
        this.esDao = esDao;
        //this.titandb = titandb;
        //this.graph = this.titandb.getTitanGraph();
        //this.g = this.graph.traversal();
    }



    public String entityExpansionService(String query){
        /*
        1) parse query to multiple token;
        2) search every token;
        3) return <token, expansion> pair;
         */

        String analyzer_str = AnalyzerNames.ik_smart;
        List<String> tokenList = AnalysisService.getTokenTermList(this.esDao, query, analyzer_str);
        logger.debug("[token list] length = " + tokenList.size() );

        Set<String> tokens = new HashSet<>(tokenList);

        Map<String, List<String> > expansions = entityExpansion(tokens);

        String json = GraphServiceHelper.outputMapToJson( expansions );

        return json;

    }

    public Map< String, List<String> > entityExpansion(Set<String> tokens){
        Map<String, List<String> > map = new HashMap<>();
        for(String token: tokens){
            List<String> expansion = entityExpansionByToken(token);
            map.put(token, expansion);
        }
        return map;
    }

    public List<String> entityExpansionByToken(String token){
        List<String> instance = new ArrayList<>();
        instance.add(token);
        List<String> instance1 = expansionConcept(token);
        List<String> instance2 = expansionInstance(token);
        instance.addAll(instance1);
        instance.addAll(instance2);
        Set<String> ins_set = new HashSet<>(instance);
        List<String> ins = new ArrayList<>(ins_set);
        return ins;
    }

    public List<String> expansionConcept(String token){
        logger.debug("[expansionConcept] ----- into method ----- ");
        List<String> instances = new ArrayList<>();
        //logger.debug("graph node size = "  );
        GraphTraversal vertexes = this.g.V()
                .has(CommonSchema.Properties.has_name_zh , token )
                .hasLabel(ConceptSchema.Properties.has_label_value )
                .outE(ConceptSchema.Edges.has_instance )
                .inV();
                //.values( CommonSchema.Properties.has_name_zh );

        while( vertexes.hasNext() ){
            Vertex vertex = (Vertex)vertexes.next();
            String name = GraphServiceHelper.getNameZh(vertex);
            String idstr = vertex.toString();
            logger.debug("[expansionConcept] instance = " + idstr + ", name = " + name);
            instances.add(name);
            // backup vertex properties
            // GraphServiceHelper.printAllProperties(vertex);
        }
        //for(int i = 0; i < instances.size(); i++) System.out.println(instances.get(i));
        return instances;
    }



    public List<String> expansionInstance(String token){
        logger.debug("[expansionInstance] into method");
        List<String> concepts = new ArrayList<>();
        GraphTraversal conVertexes = this.g.V()
                .has(CommonSchema.Properties.has_name_zh, token)
                .hasLabel(InstanceSchema.Properties.has_label_value)
                .inE(ConceptSchema.Edges.has_instance)   //get concepts, refactor to outE begin with instance
                .outV();
        while( conVertexes.hasNext() ){
            Vertex vertex = (Vertex)conVertexes.next();
            String name = GraphServiceHelper.getNameZh(vertex);
            String idstr = vertex.toString();
            logger.debug("[expansionInstance] concept = " + idstr + ", name = " + name);
            concepts.add(name);
        }
        // get all instance directly
        List<String> instances = new ArrayList<>();
        GraphTraversal vertexes = this.g.V()
                .has(CommonSchema.Properties.has_name_zh, token )
                .hasLabel(InstanceSchema.Properties.has_label_value )
                .inE( ConceptSchema.Edges.has_instance )   //get concepts, refactor to outE begin with instance
                .outV()
                .outE( ConceptSchema.Edges.has_instance )
                .inV();  // add select for token itself
        while( vertexes.hasNext() ){
            Vertex vertex = (Vertex)vertexes.next();
            String name = GraphServiceHelper.getNameZh(vertex);
            String idstr = vertex.toString();
            logger.debug("[expansionInstance] instance = " + idstr + ", name = " + name);
            if(!name.equals(token))  instances.add(name);
        }
        instances.addAll(concepts);
        return instances;
    }



    /*****************************
     *
     * @param args
     */
    public static void main(String[] args){
        EntityExpansionService service = new EntityExpansionService(new ElasticSearchDao("debug"));//, new TitanGraphDao("debug") );
        String json = service.entityExpansionService("金针菇不好吃");
        System.out.println(json);

        /*
        List<String> expansions = service.expansionConcept("食用菌");
        for(int i = 0; i < expansions.size(); i++){
            System.out.println(expansions.get(i));
        }
        */

        /*
        List<String> instances = service.expansionInstance("金针菇");
        for(int i = 0; i < instances.size(); i++){
            System.out.println(instances.get(i));
        }
        */
        /*
        List<String> ins = service.conceptExpansionByToken("金针菇");
        for(int i = 0; i < ins.size(); i++){
            System.out.println(ins.get(i));
        }
        System.out.println("execution finished");
        */
    }

}
